#include "Tracer.h"
#include "GpioInput.h"

#define PIN_GET_MS 100     /* 100ms读取一次 */

namespace libemb{
GpioInput::GpioInput()
{
    m_gpioList.clear();
    m_listenerList.clear();
    m_mainThread.start(this);
}

GpioInput::~GpioInput()
{
    std::list<InputGpio*>::iterator iter;
    for (iter = m_gpioList.begin(); iter != m_gpioList.end();iter++) 
    {
        DEL_OBJ(*iter);
    }
    m_gpioList.clear();
    m_listenerList.clear();
}
/**
 *  \brief  加入GPIO到输入监测
 *  \param  gpioName GPIO名称(如"GPIO3:12")
 *  \param  enValue  使能时GPIO值(GPIO::LOW or GPIO::HIGH)
 *  \param  msDelay  有效使能时长
 *  \return 成功返回true，失败返回false
 *  \note   比如"GPIO1:10"为输入引脚,使能电平为高电平,按下3秒后生效,则调用方法是addGpio("GPIO1:10",GPIO::HIGH,3000)
 */
bool GpioInput::addGpio(std::string gpioName,int enValue,int msDelay)
{
    AutoLock lock(&m_gpioLock);
    if (gpioName.empty()) 
    {
        return false;
    }
    enValue = (enValue == 0)?(GPIO::LOW):(GPIO::HIGH);

    std::list<InputGpio*>::iterator iter;
    for (iter = m_gpioList.begin(); iter != m_gpioList.end();iter++) 
    {
        if ((*iter)->m_name==gpioName) 
        {
            return false;
        }
    }
    InputGpio *gpio = NEW_OBJ InputGpio();
    gpio->m_name = gpioName;
    gpio->m_enValue = enValue;
    gpio->m_msDelay = (msDelay<PIN_GET_MS)?PIN_GET_MS:(msDelay/PIN_GET_MS)*PIN_GET_MS;
    gpio->m_msTime = 0;
    gpio->m_status = GPIO_STATUS_UP;
    gpio->m_gpio = GpioFactory::getInstance()->getGpioImp(gpioName);
    if (gpio->m_gpio==NULL) 
    {
        DEL_OBJ(gpio);
        return false;
    }
    if(STATUS_ERROR==gpio->m_gpio->config(GPIO::IN))
    {
        DEL_OBJ(gpio);
        return false;
    }
    m_gpioList.push_back(gpio);
    return true;
}
/**
 *  \brief  从输入监测中删除GPIO
 *  \param  gpioName GPIO名称(如"GPIO3:12")
 *  \return 成功返回true，失败返回false
 *  \note   比如"GPIO1:10"为输入引脚,使能电平为高电平,按下3秒后生效,
 *          则调用方法是addGpio("GPIO1:10",GPIO::HIGH,3000)
 */
bool GpioInput::delGpio(std::string gpioName)
{
    AutoLock lock(&m_gpioLock);
    if (gpioName.empty()) 
    {
        return false;
    }
    std::list<InputGpio*>::iterator iter;
    for (iter = m_gpioList.begin(); iter != m_gpioList.end();iter++) 
    {
        if ((*iter)->m_name==gpioName) 
        {
            DEL_OBJ(*iter);
            m_gpioList.erase(iter);
            break;
        }
    }
    return true;
}
/**
 *  \brief  注册GPIO监听者
 *  \param  gpioListener GPIO监听者
 *  \return void
 *  \note   注册后,事件监听者需要实现handleGpio来处理按键事件
 */
void GpioInput::registerGpioListener(GpioListener* gpioListener)
{
    AutoLock lock(&m_listenerLock);
    m_listenerList.push_back(gpioListener);
}
/**
 *  \brief  取消注册GPIO事件监听者
 *  \param  gpioListener GPIO监听者
 *  \return void
 *  \note   none
 */
void GpioInput::unregisterGpioListener(GpioListener* gpioListener)
{
    AutoLock lock(&m_listenerLock);
    m_listenerList.remove(gpioListener);  
}

void GpioInput::run()
{
    while (1) 
    {
        std::list<InputGpio*>::iterator gpioIter;
        m_gpioLock.lock();
        for (gpioIter = m_gpioList.begin(); gpioIter != m_gpioList.end();gpioIter++)
        {
            InputGpio* gpio = *gpioIter;
            if (gpio->m_gpio->getPinValue() == gpio->m_enValue)
            {
                gpio->m_msTime += PIN_GET_MS;
                if (gpio->m_msTime == gpio->m_msDelay) 
                {
                    if (gpio->m_status != GPIO_STATUS_DOWN) 
                    {
                        gpio->m_status = GPIO_STATUS_DOWN;    
                    }
                    AutoLock lock(&m_listenerLock);
                    std::list<GpioListener*>::iterator listenerIter;
                    for (listenerIter=m_listenerList.begin();listenerIter!=m_listenerList.end();listenerIter++) 
                    {
                        (*listenerIter)->handleGpio(gpio->m_name, gpio->m_status);
                    }
                }
                else if (gpio->m_msTime > gpio->m_msDelay) 
                {
                    gpio->m_msTime = gpio->m_msDelay;
                }
            }
            else
            {
                gpio->m_msTime = 0;
                if (gpio->m_status==GPIO_STATUS_DOWN) 
                {
                    gpio->m_status=GPIO_STATUS_UP;
                    AutoLock lock(&m_listenerLock);
                    std::list<GpioListener*>::iterator listenerIter;
                    for (listenerIter=m_listenerList.begin();listenerIter!=m_listenerList.end();listenerIter++) 
                    {
                        (*listenerIter)->handleGpio(gpio->m_name, gpio->m_status);
                    }
                }
            }
        }
        m_gpioLock.unLock();
        Thread::msleep(PIN_GET_MS);
    }
}
}
